﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using BillGuru.Persistence;

namespace BillGuru
{
    public partial class FrmInvoice : Form
    {
        public FrmInvoice()
        {
            InitializeComponent();
        }

        private int invoiceId = -1;
        public int InvoiceId { get { return invoiceId; } set { invoiceId = value; } }    

        private void LoadInvoice(int nInvoiceID)
        {

            string sInvoiceCommand = "Select * from Invoice where ID = " + nInvoiceID;
            string sInvoiceLineItemsCommand = "Select * from InvoiceLineItem where InvoiceID = " + nInvoiceID;

            System.Data.OleDb.OleDbDataAdapter invoiceTableAdapter = new System.Data.OleDb.OleDbDataAdapter();
            invoiceTableAdapter.SelectCommand = new System.Data.OleDb.OleDbCommand(sInvoiceCommand, new System.Data.OleDb.OleDbConnection(BillGuru.Properties.Settings.Default.BillGuruConnectionString));

            System.Data.OleDb.OleDbDataAdapter invoiceLineItemTableAdapter = new System.Data.OleDb.OleDbDataAdapter();
            invoiceLineItemTableAdapter.SelectCommand = new System.Data.OleDb.OleDbCommand(sInvoiceLineItemsCommand, new System.Data.OleDb.OleDbConnection(BillGuru.Properties.Settings.Default.BillGuruConnectionString));

            invoiceTableAdapter.Fill(billGuruDataSet.Invoice);
            invoiceLineItemTableAdapter.Fill(billGuruDataSet.InvoiceLineItem);

            selectCompanyOnInvoiceLoad();
            selectInvoiceTypeOnInvoiceLoad();
            this.dptInvoiceDate.Value = billGuruDataSet.Invoice[0].InvoiceDate;
            InvoiceType invoiceType = getInvoiceType((int)cbInvoiceType.SelectedValue);

            if (invoiceType == InvoiceType.Sale)
                selectCustomerOnInvoiceLoad();
            else
                selectVendorOnInvoiceLoad();

            adaptControlsToInvoiceType(invoiceType);


        }

        private void selectInvoiceTypeOnInvoiceLoad()
        {
            int InvoiceTypeId = billGuruDataSet.Invoice[0].InvoiceTypeID;
            int index = 0;
            foreach (BillGuruDataSet.InvoiceTypeRow row in billGuruDataSet.InvoiceType)
            {
                if (row.ID != InvoiceTypeId)
                    index++;
                else
                    break;
            }

            cbInvoiceType.SelectedIndex = index;

        }

        private void selectCustomerOnInvoiceLoad()
        {
            int CustomerId = billGuruDataSet.Invoice[0].CustomerID;
            int index = 0;
            foreach (BillGuruDataSet.CustomerRow row in billGuruDataSet.Customer)
            {
                if (row.ID != CustomerId)
                    index++;
                else
                    break;
            }

            cbCustomer.SelectedIndex = index;

        }

        private void selectVendorOnInvoiceLoad()
        {
            int VendorId = billGuruDataSet.Invoice[0].VendorID;
            int index = 0;
            foreach (BillGuruDataSet.VendorRow row in billGuruDataSet.Vendor)
            {
                if (row.ID != VendorId)
                    index++;
                else
                    break;
            }

            cbVendor.SelectedIndex = index;

        }

        private void selectCompanyOnInvoiceLoad()
        {
            int CompanyId = billGuruDataSet.Invoice[0].CompanyID;
            int index = 0;
            foreach (BillGuruDataSet.CompanyRow row in billGuruDataSet.Company)
            {
                if (row.ID != CompanyId)
                    index++;
                else
                    break;
            }

            cbCompany.SelectedIndex = index;

        }

        private void FrmInvoice_Load(object sender, EventArgs e)
        {
            this.productTableAdapter.Fill(this.billGuruDataSet.Product);
            //            this.invoiceLineItemTableAdapter.Fill(this.billGuruDataSet.InvoiceLineItem);
            //            this.invoiceTableAdapter.Fill(this.billGuruDataSet.Invoice);
            this.customerTableAdapter.Fill(this.billGuruDataSet.Customer);
            this.vendorTableAdapter.Fill(this.billGuruDataSet.Vendor);
            this.companyTableAdapter.Fill(this.billGuruDataSet.Company);
            this.invoiceTypeTableAdapter.Fill(this.billGuruDataSet.InvoiceType);

            this.invoiceTableAdapter.Adapter.RowUpdated += new System.Data.OleDb.OleDbRowUpdatedEventHandler(Adapter_RowUpdated);
            this.invoiceLineItemTableAdapter.Adapter.RowUpdated += new System.Data.OleDb.OleDbRowUpdatedEventHandler(Adapter_RowUpdated);
            this.invoiceLineItemTableAdapter.Adapter.RowUpdated += new System.Data.OleDb.OleDbRowUpdatedEventHandler(UpdateStock);


            this.cbInvoiceType.SelectedIndex = 0; // Select Purchase as default
            adaptControlsToInvoiceType(cbInvoiceType.Text);

            if (invoiceId != -1)
            {
                LoadInvoice(invoiceId);
            }

        }

        void UpdateStock(object sender, System.Data.OleDb.OleDbRowUpdatedEventArgs e)
        {
            float fDiff = 0;
            int nSwap = (getInvoiceType(cbInvoiceType.SelectedText) == InvoiceType.Sale) ? 1 : -1;

            if (e.StatementType == StatementType.Insert)
                fDiff = (float)e.Row["Quantity"];
            else if (e.StatementType == StatementType.Update)
                fDiff = nSwap * ((float)e.Row["Quantity"] - (float)e.Row["Quantity", DataRowVersion.Original]);
            else if (e.StatementType == StatementType.Delete)
                fDiff = -(nSwap * (float)(e.Row["Quantity", DataRowVersion.Original]));

            int pID;
            if (e.Row.HasVersion(DataRowVersion.Current))
                pID = (int)e.Row["ProductID", DataRowVersion.Current];
            else if (e.Row.HasVersion(DataRowVersion.Original))
                pID = (int)e.Row["ProductID", DataRowVersion.Original];
            else
                throw new InvalidOperationException();

            BillGuruDataSet.ProductRow[] productRows = (BillGuruDataSet.ProductRow[])billGuruDataSet.Product.Select("ID = " + pID);
            if (productRows == null || productRows.Count() != 1)
                throw new InvalidOperationException();

            BillGuruDataSet.ProductRow productRow = productRows[0];

            productRow.Stock -= (int)fDiff;
            this.productTableAdapter.Update(productRow);
        }

        void Adapter_RowUpdated(object sender, System.Data.OleDb.OleDbRowUpdatedEventArgs e)
        {
            SharedEventHandlerImpl.RetrieveKeyOnRowInsert(sender, e);
        }

        private void invoiceTypeIDComboBox_SelectionChangeCommitted(object sender, EventArgs e)
        {
            ComboBox cbType = (ComboBox)sender;
            DataRowView row = (DataRowView)cbType.SelectedItem;
            string type = row.Row.Field<string>("InvoiceType");
            adaptControlsToInvoiceType(type);
        }

        private void adaptControlsToInvoiceType(string typeText)
        {
            InvoiceType type = getInvoiceType(typeText);

            adaptControlsToInvoiceType(type);
        }

        private void adaptControlsToInvoiceType(InvoiceType type)
        {
            if (type == InvoiceType.Sale)
            {
                this.cbVendor.Visible = false;
                this.vendorIDLabel.Visible = false;
                this.cbCustomer.Visible = true;
                this.customerIDLabel.Visible = true;
            }
            else if (type == InvoiceType.Purchase)
            {
                this.cbVendor.Visible = true;
                this.vendorIDLabel.Visible = true;
                this.cbCustomer.Visible = false;
                this.customerIDLabel.Visible = false;
            }
        }

        private void tbFilter_Validated(object sender, EventArgs e)
        {
            applyFilter(tbFilter.Text);
        }

        private void applyFilter(string sExistingFilter)
        {
            string sFilter = BillGuru.Utilities.DatabaseUtilities.createProductDescriptionFilter(sExistingFilter);

            productSearchBindingSource.Filter = sFilter;
        }

        private void clearFilter()
        {
            productSearchBindingSource.Filter = "";
        }

        private void invoiceLineItemDataGridView_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {

        }

        private void invoiceLineItemDataGridView_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex == invoiceLineItemDataGridView.Columns["Delete"].Index
                && !invoiceLineItemDataGridView.Rows[e.RowIndex].IsNewRow)
                invoiceLineItemDataGridView.Rows.Remove(invoiceLineItemDataGridView.Rows[e.RowIndex]);

        }

        private void invoiceLineItemDataGridView_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        {
            DataGridViewComboBoxEditingControl ctr = e.Control as DataGridViewComboBoxEditingControl;
            if (ctr == null)
                return;

            ctr.DataSource = productSearchBindingSource;

        }

        private void invoiceLineItemDataGridView_CellValidated(object sender, DataGridViewCellEventArgs e)
        {
            DataGridViewRow gridrow = invoiceLineItemDataGridView.Rows[e.RowIndex];

            if (gridrow.Cells["Product"].Value == DBNull.Value)
                return;

            if (e.ColumnIndex == invoiceLineItemDataGridView.Columns["Product"].Index)
            {
                string sFilter = "ID=" + gridrow.Cells["Product"].Value;
                BillGuruDataSet.ProductRow productRow = (BillGuruDataSet.ProductRow)billGuruDataSet.Product.Select(sFilter)[0];
                gridrow.Cells["SalePrice"].Value = productRow.SellingPrice;
                gridrow.Cells["Discount"].Value = productRow.Discount;
                gridrow.Cells["Quantity"].Value = 1;
            }
            else if (gridrow.Cells["Product"].Value != DBNull.Value)
            {
                float fSalePrice = float.Parse(gridrow.Cells["SalePrice"].Value.ToString());
                float fDisc = float.Parse(gridrow.Cells["Discount"].Value.ToString());
                float fQty = float.Parse(gridrow.Cells["Quantity"].Value.ToString());

                float fPrice = fSalePrice - (fSalePrice * (fDisc / 100f));
                float fSubTotal = fPrice * fQty;

                gridrow.Cells["SubTotal"].Value = fSubTotal;
            }

        }

        private void pbDone_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void FrmInvoice_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (this.billGuruDataSet.HasChanges())
                BillGuru.UI.PermissionHandler.checkDataLoss(e);
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (keyData == (Keys.Control | Keys.F))
            {
                this.tbFilter.Focus();
                this.tbFilter.SelectAll();
                return true;
            }

            return base.ProcessCmdKey(ref msg, keyData);
        }

        private void pbSave_Click(object sender, EventArgs e)
        {
            BillGuruDataSet.InvoiceRow invoice;


            if (billGuruDataSet.Invoice.Rows.Count == 0)
            {
                invoice = billGuruDataSet.Invoice.NewInvoiceRow();
                billGuruDataSet.Invoice.AddInvoiceRow(invoice);
            }
            else
                invoice = (BillGuruDataSet.InvoiceRow)billGuruDataSet.Invoice.Rows[0];

            InvoiceType selectedInvoiceType = getInvoiceType(cbInvoiceType.Text);
            InvoiceType existingInvoiceType = getInvoiceType(invoice.InvoiceTypeID);

            if (existingInvoiceType != InvoiceType.Unknown)
                if (existingInvoiceType != selectedInvoiceType)
                {
                    MessageBox.Show("Cannot change invoice types", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

            invoice.CompanyID = (int)cbCompany.SelectedValue;
            invoice.InvoiceDate = this.dptInvoiceDate.Value;
            invoice.InvoiceTypeID = (int)cbInvoiceType.SelectedValue;


            if (selectedInvoiceType == InvoiceType.Sale)
                invoice.CustomerID = (int)cbCustomer.SelectedValue;
            else if (selectedInvoiceType == InvoiceType.Purchase)
                invoice.VendorID = (int)cbVendor.SelectedValue;

            invoice.InvoiceStatus = cInvoiceStatus[(int)InvoiceStatus.Incomplete];

            invoiceTableAdapter.Update(billGuruDataSet.Invoice);

            foreach (BillGuruDataSet.InvoiceLineItemRow row in billGuruDataSet.InvoiceLineItem)
            {
                if (row.RowState == DataRowState.Added)
                    row.InvoiceID = ((BillGuruDataSet.InvoiceRow)billGuruDataSet.Invoice.Rows[0]).ID;
            }

            invoiceLineItemTableAdapter.Update(billGuruDataSet.InvoiceLineItem);
        }

        private InvoiceType getInvoiceType(int p)
        {
            switch (p)
            {
                case 1:
                    return InvoiceType.Sale;

                case 2:
                    return InvoiceType.Purchase;

                default:
                    return InvoiceType.Unknown;
            }
        }

        private InvoiceType getInvoiceType(string typeText)
        {
            if (typeText == "Sales")
                return InvoiceType.Sale;
            else if (typeText == "Purchase")
                return InvoiceType.Purchase;
            else
                return InvoiceType.Unknown;

        }

        enum InvoiceType
        {
            Sale,
            Purchase,
            Unknown
        }

        enum InvoiceStatus
        {
            Incomplete,
            Complete
        }

        private string[] cInvoiceStatus = { "I", "C" };

        private void pbPrint_Click(object sender, EventArgs e)
        {

        }
    }
}
